package mobileann.mafamily.utils;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import mobileann.mafamily.act.main.FS;
import mobileann.mafamily.db.model.EZoneDBModel;
import mobileann.mafamily.db.model.LocationTrackModel;
import mobileann.mafamily.entity.EleEntity;
import mobileann.mafamily.entity.LocationEntity;
import mobileann.mafamily.entity.LocationTrackBean;
import mobileann.mafamily.entity.MessageBean;
import mobileann.mafamily.model.UDPSocket;
import mobileann.mafamily.movestateimprove.MAWakeLockManager;
import mobileann.mafamily.service.MainService;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.os.PowerManager;
import android.text.TextUtils;

import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.location.LocationClientOption.LocationMode;
import com.baidu.mapapi.model.LatLng;
import com.baidu.mapapi.utils.DistanceUtil;
import com.mofind.android.base.L;
import com.mofind.android.net.HttpUtils;
import com.mofind.java.utils.TimeUtils;

/**
 * 主要功能:
 * <br> 百度地图定位, 目前包括在线定位和离线定位
 * @annotation ADRIAN.2015.8.11.10.37
 *
 */
public class BaiduLocationUtils implements MapTag {

	private static BaiduLocationUtils _instance = null;
	// 记录上一个点, 看看这个点是否无效(针对离线定位)
	private String recordStrTime = "";
	private double recordLatitude;
	private double recordLongitude;

	public static synchronized BaiduLocationUtils getInstance(Context c) {
		if (_instance == null) {
			_instance = new BaiduLocationUtils(FS.getInstance());
		}
		return _instance;
	}

	private Context mContext;

	// 定位相关
	public LocationClient mLocClient = null;
	private String myCity;

	public static final String KEY_MAP = "0LaBu7jnh1OjMarwnixnkyOk";
	private static final String URL_GET_ADDR_STRING = "http://api.map.baidu.com/geocoder/v2/?ak=%s&location=%s,%s&output=json";

	private BaiduLocationUtils(Context c) {
		mContext = FS.getInstance();
		//
		arrRequestList = new ArrayList<Integer>();
		hlStopLoc = new Handler() {
			public void handleMessage(Message msg) {
				switch (msg.what) {
				case 1:	                
					synchronized (arrRequestList) {
						if (arrRequestList.size() > 0) {
							arrRequestList.remove(0);
							//
							LocationEntity loc = new LocationEntity(SPUtils.getUID(),
									SPUtils.getFID(), (MainService.iCurrLongitude / 1e6),
									(MainService.iCurrLatitude / 1e6), 
									String.valueOf(TimeUtils.getDateTimeStr(System.currentTimeMillis())),
									"未知位置",
									String.valueOf(LocationUtis.UNKNOWN_LOCATE));
							if (locationListener != null) {
								locationListener.onReceiveLocation(loc);
							}

							if (locListener != null) {
								locListener.onUploadLocation(loc);
							}
							//
							if (FS.getLoginState()) {
								L.e("上传当前timeout位置: (" + loc.getLatitude() + ", "
										+ loc.getLongitude() + ") ");
								int theX = (int) (loc.getLatitude() * 1e6);
								int theY = (int) (loc.getLongitude() * 1e6);                    
								UDPSocket.getInstance(FS.getInstance())
								.sendLocationRequestOfflineOrNull(String.valueOf(theX),
										String.valueOf(theY), 
										"no address", 
										String.valueOf(55));                    
							}
						}
						if (arrRequestList.size() > 0) {                            
							setTimeout();
							startLocation();
							int ilocRet = mLocClient.requestLocation();
							L.e("上传发起定位的结果: (" + ilocRet + ") ");
							if (ilocRet != 0) {
								cancelTimeout();
								hlStopLoc.obtainMessage(1).sendToTarget();
							}
						} else {
							stopLocation();
						}
					}
					break;
				case 2:
					cancelTimeout();	                	              
					synchronized (arrRequestList) {
						if (arrRequestList.size() > 0) {
							arrRequestList.remove(0);
						}
						if (arrRequestList.size() > 0) {                            
							setTimeout();
							startLocation();
							int ilocRet = mLocClient.requestLocation();
							L.e("上传发起定位的结果: (" + ilocRet + ") ");
							if (ilocRet != 0) {
								cancelTimeout();
								hlStopLoc.obtainMessage(1).sendToTarget();
							}
						} else {
							stopLocation();
						}
					}
					break;
				}
			}
		};	    
	}

	@Override
	public void requestLocation() {
		synchronized (arrRequestList) {
			arrRequestList.add(Integer.valueOf(1));
			if (arrRequestList.size() == 1) {
				setTimeout();
				//
				startLocation();
				//
				int ilocRet = mLocClient.requestLocation();
				L.e("上传发起定位的结果: (" + ilocRet + ") ");
				if (ilocRet != 0) {
					cancelTimeout();
					hlStopLoc.obtainMessage(1).sendToTarget();
				}
			}
		}
	}

	private ArrayList<Integer> arrRequestList = null;
	private Handler hlStopLoc;

	private Thread thdTimeout = null;
	private byte[] blk = new byte[0];

	private void setTimeout() {
		cancelTimeout();
		synchronized (blk) {
			thdTimeout = new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						Thread.sleep(10000);
						hlStopLoc.obtainMessage(1).sendToTarget();
					} catch (InterruptedException e) {
						L.e("maf", "error--", e);
					}
				}
			});
			thdTimeout.start();
		}
	}

	private void cancelTimeout() {
		synchronized (blk) {
			if (thdTimeout != null) {
				thdTimeout.interrupt();
				try {
					thdTimeout.join(2000);
				} catch (InterruptedException e) {
					L.e("maf", "error--", e);
				}
				thdTimeout = null;
			}
		}        
	}

	private synchronized void startLocation() {		    
		MAWakeLockManager.AcquireLock(FS.getInstance(), "BaiduLocationUtils-Lock", PowerManager.PARTIAL_WAKE_LOCK);
		if (mLocClient != null) {
			if (!mLocClient.isStarted()) mLocClient.start();
		} else {
			mLocClient = new LocationClient(FS.getInstance());
			mLocClient.registerLocationListener(mLocationListenner); // 设置定位监听
			mLocClient.setLocOption(getLocationOption()); // 设置相关参数
			mLocClient.start();
		}		
	}

	private synchronized void stopLocation() {
		if (mLocClient != null) {
			//			mLocClient.stop();	// 这里屏蔽掉，因为开关服务并非异步，并导致requestlocation返回值出错，进而触发超时处理去关闭服务，进而导致后续排队的请求得不到处理，导致位置不动				
		}
		MAWakeLockManager.ReleaseLock("BaiduLocationUtils-Lock");
	}

	/**
	 * 设置相关参数
	 */
	private LocationClientOption getLocationOption() {
		LocationClientOption option = new LocationClientOption();
		option.setCoorType("bd09ll");// 百度定位SDK可以返回三种坐标系，分别是bd09, bd09ll和gcj02
		option.setIsNeedAddress(true);
		option.setLocationMode(LocationMode.Battery_Saving); // 高精度定位(GPS+WIFI+基站)		
		return option;
	}
	/**
	 * 重置相关参数
	 */
	private void resetLocOption(){
		mLocClient.setLocOption(getLocationOption());
	}

	private double getdistance(int i, int i2, int j, int j2) {
		LatLng p1LL = new LatLng((double) i / 1e6, (double) i2 / 1e6);
		LatLng p2LL = new LatLng((double) j / 1e6, (double) j2 / 1e6);
		double distance = DistanceUtil.getDistance(p1LL, p2LL);
		return distance;
	}

	/**
	 * 查看本人是否处于某个围栏
	 * 
	 * @param x
	 *            当前坐标x
	 * @param y
	 *            当前坐标y
	 * @return 围栏名称（没有则为空）
	 */
	private String CheckELE(int x, int y) {
		String point2 = "";
		try { // 这里经常报错, 所以加一个try-catch块结构, 如果出错则返回空""
			List<EleEntity> elelist2 = EZoneDBModel.queryAll(FS.getInstance());
			if (elelist2 != null && elelist2.size() > 0) {
				for (int i = 0, count = elelist2.size(); i < count; i++) {
					if(!TextUtils.isEmpty(elelist2.get(i).getLatitude())){//友盟统计中有报空指针异常
						int c1 = Integer.valueOf(elelist2.get(i).getLatitude());
						int c2 = Integer.valueOf(elelist2.get(i).getLongitude());
						double distance = getdistance(x, y, c1, c2);
						double radius = Double.valueOf(elelist2.get(i).getRadius());
						if (distance <= radius) {
							point2 = (String) elelist2.get(i).getDesc();
							return point2;
						}
					}
				}
			}
		} catch (NumberFormatException e) {
//			e.printStackTrace();
			point2 = "";
		}
		return point2;
	}

	/**
	 * 记录当前所处围栏名称，并在符合条件时发送系统消息
	 * 
	 * @param x
	 *            坐标x
	 * @param y
	 *            坐标y
	 */
	private void SetELENAME(int x, int y) {
		String sr = CheckELE(x, y);
		String elename = SPUtils.getELENAME();
		if (sr.equals(elename)) {
		} else {
			SimpleDateFormat formatter = new SimpleDateFormat("MM月dd日 HH:mm:ss");
			if (sr.equals("")) {
				MessageBean msg = new MessageBean();
				msg.setFid(SPUtils.getFID());
				msg.setUid(SPUtils.getUID());
				msg.setSort(MessageBean.SYSTEM);
				msg.setTime(formatter.format(new Date()));
				msg.setText("已离开 < " + elename + " > ");
				UDPSocket.getInstance(FS.getInstance()).Send_Message_toServer(msg);
				SPUtils.setELENAME(sr);
			} else if (elename.equals("")) {
				MessageBean msg = new MessageBean();
				msg.setFid(SPUtils.getFID());
				msg.setUid(SPUtils.getUID());
				msg.setSort(MessageBean.SYSTEM);
				msg.setTime(formatter.format(new Date()));
				msg.setText("已到 < " + sr + " > ");
				UDPSocket.getInstance(FS.getInstance()).Send_Message_toServer(
						msg);
				SPUtils.setELENAME(sr);
			} else {
				MessageBean msg = new MessageBean();
				msg.setFid(SPUtils.getFID());
				msg.setUid(SPUtils.getUID());
				msg.setSort(MessageBean.SYSTEM);
				msg.setTime(formatter.format(new Date()));
				msg.setText("已离开 < " + elename + " > ，同时已到 < " + sr
						+ " > ");
				UDPSocket.getInstance(FS.getInstance()).Send_Message_toServer(
						msg);
				SPUtils.setELENAME(sr);
			}
		}
	}

	private static final double WEST_POINT = 72.000000f;
	private static final double EAST_POINT = 136.000000f;
	private static final double NORTH_POINT = 54.000000f;
	private static final double SOUTH_POINT = 3.000000f;

	/**
	 * 判断此点是否是有效点 &ADRIAN.2015.8.14.16.38
	 * @param location
	 * @return
	 * @annotation ADRIAN.2015.8.14.16.38
	 */
	private boolean IsaValidLocation(BDLocation location) {
		boolean bret = false;
		double latitude = location.getLatitude();
		double longitude = location.getLongitude();
		if ((longitude > WEST_POINT) && (longitude < EAST_POINT)
				&& (latitude > SOUTH_POINT) && (latitude < NORTH_POINT)) {
			bret = true;
		}
		return bret;
	}

	/**
	 * 定位函数监听
	 * <br> Log是否是定位回掉信息--在主界面定位。
	 * @annotation ADRIAN 2015.7.14.15.44 
	 */
	private BDLocationListener mLocationListenner = new BDLocationListener() {

		@Override
		public void onReceiveLocation(BDLocation location) {
			if (location == null) {			    			    
				setTimeout();                
				{
					int ilret = 0;
					int iRetry = 0;
					ilret = mLocClient.requestLocation();
					L.e("上传NULL再次发起定位的结果: (" + ilret + ") ");
					if (ilret != 0) {
						while (ilret == 6) {
							iRetry++;
							try {
								Thread.sleep(1000);
								setTimeout();
								ilret = mLocClient.requestLocation();
								L.e("上传NULL再次发起定位的结果: (" + ilret + ") ");
							} catch (InterruptedException e) {
								L.e("maf", "error--", e);
							}  
							if (iRetry >= 2) {
								break;
							}
						}
					}                
				}

				return;
			}
			if (!IsaValidLocation(location)) {
				LocationEntity loc = new LocationEntity(
						SPUtils.getUID(),
						SPUtils.getFID(),
						(MainService.iCurrLongitude / 1e6),
						(MainService.iCurrLatitude / 1e6),
						String.valueOf(TimeUtils.getDateTimeStr(System.currentTimeMillis())),
						"未知位置",
						String.valueOf(LocationUtis.UNKNOWN_LOCATE));
				if (locationListener != null) {
					locationListener.onReceiveLocation(loc);
				}
				if (locListener != null) {
					locListener.onUploadLocation(loc);
				}
				if (FS.getLoginState()) {
					//                    L.e("上传当前非法位置: (" + location.getLatitude() + ", "+ location.getLongitude() + ") ");
					int theX = (int) (location.getLatitude() * 1e6);
					int theY = (int) (location.getLongitude() * 1e6);                    
					UDPSocket.getInstance(FS.getInstance()).sendLocationRequestOfflineOrNull(
							String.valueOf(theX),
							String.valueOf(theY),
							"no address", 
							String.valueOf(33));
				}
				hlStopLoc.obtainMessage(2).sendToTarget();
				return;
			}
			/*
			 * 返回值： 
			 * 61 ： GPS定位结果 
			 * 62 ： 扫描整合定位依据失败。此时定位结果无效。 
			 * 63 ：网络异常，没有成功向服务器发起请求。此时定位结果无效。 
			 * 65 ： 定位缓存的结果。 
			 * 66 ：离线定位结果。通过requestOfflineLocaiton调用时对应的返回结果 
			 * 67 ：离线定位失败。通过requestOfflineLocaiton调用时对应的返回结果 
			 * 68 ：网络连接失败时，查找本地离线定位时对应的返回结果 
			 * 161： 表示网络定位结果 
			 * 162~167： 服务端定位失败。
			 */
			myCity = location.getCity();
			int iretType = location.getLocType();
			L.e("gpc-get loc", "loc return code:============" + iretType);
			if (iretType==66){
//				insertOfflineTrackInfo(location, LocationUtis.OFFLINE_LOCATE); // 添加离线定位记录 &ADRIAN.2015.7.31.15.01
			}else if (iretType==68 || iretType==65) { //网络连接定位失败&定位缓存的结果				
//				if (FS.getLoginState()) {
//					int theX = (int) (location.getLatitude() * 1e6);
//					int theY = (int) (location.getLongitude() * 1e6);                    
//					UDPSocket.getInstance(FS.getInstance()).sendLocationRequestOfflineOrNull(String.valueOf(theX),
//							String.valueOf(theY), 
//							"no address", 
//							String.valueOf(LocationUtis.OFFLINE_LOCATE));                    
//				}
			} else if ( iretType == 61 || iretType == 161 ) { // 网络连接成功
				String strAddress = location.getAddrStr();
				String locate_type = null;
				if (TextUtils.isEmpty(strAddress)) { // 增加定位类型 &ADRIAN.2015.8.12.16.29
					strAddress = null;
					strAddress = "未知位置";
					locate_type = String.valueOf(LocationUtis.UNKNOWN_LOCATE);
				} else {
					//	if (NetUtils.getInstance().isWifiEnabled()) {
					//	locate_type = String.valueOf(LocationUtis.WIFI_LOCATE);
					//	} else {
					//	locate_type = String.valueOf(LocationUtis.MOBILE_LOCATE);
					//	}
					// 0(离线状态) 1(移动网络) 2(只是wifi连接)
					if (NetUtils.getInstance().netstate() == 2) {
						locate_type = String.valueOf(LocationUtis.WIFI_LOCATE);
					} else if(NetUtils.getInstance().netstate() == 1) {
						locate_type = String.valueOf(LocationUtis.MOBILE_LOCATE);
					} 
				}
				LocationEntity loc = new LocationEntity(
						SPUtils.getUID(),
						SPUtils.getFID(),
						location.getLongitude(),
						location.getLatitude(), 
						String.valueOf(TimeUtils.getDateTimeStr(System.currentTimeMillis())),
						strAddress,
						locate_type);	
				if (locationListener != null) {
					locationListener.onReceiveLocation(loc);
				}
				if (locListener != null) {
					locListener.onUploadLocation(loc);
				}
				if (FS.getLoginState()) {
					//					L.e("上传当前位置: (" + loc.getLatitude() + ", " + loc.getLongitude() + ") ");
					int theX = (int) (loc.getLatitude() * 1e6);
					int theY = (int) (loc.getLongitude() * 1e6);
					MainService.iCurrLatitude = theX;
					MainService.iCurrLongitude = theY;
					MainService.iCurrLocType = LocationUtis.BASESTATION_LOCATE;  //基站
					if (iretType == 61) {
						MainService.iCurrLocType = LocationUtis.GPS_LOCATE; //GPS
					} else if (iretType == 161) {
						//					    if (NetUtils.getInstance().isWifiEnabled()) { // 此处有bug,但下面的方法会将其改写 &ADRIAN.2015.8.14.10.48
						//					        MainService.iCurrLocType = LocationUtis.WIFI_LOCATE/*1*/; //WIFI
						//					    }
						// 0(离线状态) 1(移动网络) 2(只是wifi连接)
						if (NetUtils.getInstance().netstate() == 2) {
							MainService.iCurrLocType = LocationUtis.WIFI_LOCATE;
						} else if(NetUtils.getInstance().netstate() == 1) {
							MainService.iCurrLocType = LocationUtis.MOBILE_LOCATE;
						}
					}
					//当由心跳包发起的定位为基站，计数加1
					if(MainService.iCurrLocType == LocationUtis.BASESTATION_LOCATE/*0*/
							&& FS.LOC_TAG_RTC.equals(FS.locTag)){
						int count = SPUtils.getLocTypeCount() + 1;
						SPUtils.setLocTypeCount(count);
						//	L.i("LocationMode", "Count: "+SPUtils.getLocTypeCount());
						if(SPUtils.getLocTypeCount() == 7){
							SPUtils.setFristRecordSucceed(true);
							SPUtils.setLocTypeCount(0);
						}
					}
					//	else{
					//		SPUtils.setLocTypeCount(0);
					//	}
					if(MainService.iCurrLocType == 1){
						SPUtils.setLocTypeCount(0);
					}
					// 基站定位 + 移动定位 = 移动网络定位 | // wifi定位
					UDPSocket.getInstance(FS.getInstance()).sendLocationRequest(String.valueOf(theX),
							String.valueOf(theY), "no address", 
							String.valueOf(MainService.iCurrLocType));
					SetELENAME(theX, theY);
				}
			} else {
				if (FS.getLoginState()) {
//					L.e("上传当前回调其他情况位置: (" + MainService.iCurrLatitude + ", "	+ MainService.iCurrLongitude + ") ");
					UDPSocket.getInstance(FS.getInstance()).sendLocationRequestOfflineOrNull(
							String.valueOf(MainService.iCurrLatitude),
							String.valueOf(MainService.iCurrLongitude), "no address", 
							String.valueOf(iretType));
				}
			}
			//
			hlStopLoc.obtainMessage(2).sendToTarget();
		}

		public void onReceivePoi(BDLocation poiLocation) {
			if (poiLocation == null)
				return;
		}
	};


	/**
	 * 利用GPS中存入本地的方法将离线地图所处的位置也存放到本地
	 * @param longtitude<theY> 获取到的经度
	 * @param tatitude<theX> 获取到的纬度
	 * @param location 获取到的location位置信息
	 * @annotation ADRIAN.2015.7.30.13.42
	 */
	public void insertOfflineTrackInfo(BDLocation location, int locate_type){
		
		// 判断是否是相同的点
		if (recordLatitude == location.getLatitude() && recordLongitude == location.getLongitude() 
				&& recordStrTime.equals(location.getTime())) {
			return ;
		}
		recordStrTime = location.getTime();
		recordLatitude = location.getLatitude();
		recordLongitude = location.getLongitude();
		int longtitude = (int) (location.getLongitude() * 1e6);
		int latitude = (int) (location.getLatitude()* 1e6);
//		String time = location.getTime();
		String time = String.valueOf(TimeUtils.getDateTimeStr(System.currentTimeMillis()));

		//保存坐标信息到本地
		LocationTrackBean locBean = new LocationTrackBean(SPUtils.getFID(),
				SPUtils.getUID(), longtitude, latitude, time, String.valueOf(locate_type)); 
		LocationTrackModel.insertTrackInfo(locBean, mContext);
	}

	@Override
	public void setLocationListener(FSLocListener locationListener) {
		this.locationListener = locationListener;
	}

	@Override
	public void setLocListener(BDLocListener locListener) {
		this.locListener = locListener;
	}

	private FSLocListener locationListener;
	private BDLocListener locListener;

	/**
	 * 获取地理位置
	 */
	@Override
	public void getAddrStr(LocationEntity loc, HttpUtils.HttpResultCallback callback) {
		String url = String.format(URL_GET_ADDR_STRING, KEY_MAP,
				loc.getLatitude() + "", loc.getLongitude() + "");
		HttpUtils.startHttpGet(url, callback);
	}

	@Override
	public void getAddrStr(EleEntity loc, HttpUtils.HttpResultCallback callback) {
		String url = String.format(URL_GET_ADDR_STRING, KEY_MAP,
				loc.getLatitude() + "", loc.getLongitude() + "");
		HttpUtils.startHttpGet(url, callback);
	}

	@Override
	public void getAddrStr(double latitude, double longitude,HttpUtils.HttpResultCallback callback) {
		String url = String.format(URL_GET_ADDR_STRING, KEY_MAP,
				String.valueOf(latitude),
				String.valueOf(longitude));
		HttpUtils.startHttpGet(url, callback);
	}

	@Override
	public String getMyCity() {
		return myCity;
	}

	@Override
	public String getTag() {
		return "BMap";
	}

	@Override
	public String getAddressTagWrapper() {
		return "result";
	}

	@Override
	public String getAddressTag() {
		return "formatted_address";
	}
}
